2450 #include "param.h"
2451 #include "types.h"
2452 #include "defs.h"
2453 #include "x86.h"
2454 #include "mmu.h"
2455 #include "proc.h"
2456 #include "elf.h"
2457 
2458 #define USERTOP  0xA0000
2459 
2460 static pde_t *kpgdir;  // for use in scheduler()
2461 
2462 // Set up CPU's kernel segment descriptors.
2463 // Run once at boot time on each CPU.
2464 void
2465 ksegment(void)
2466 {
2467   struct cpu *c;
2468 
2469   // Map virtual addresses to linear addresses using identity map.
2470   // Cannot share a CODE descriptor for both kernel and user
2471   // because it would have to have DPL_USR, but the CPU forbids
2472   // an interrupt from CPL=0 to DPL=3.
2473   c = &cpus[cpunum()];
2474   c->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0);
2475   c->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0);
2476   c->gdt[SEG_UCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, DPL_USER);
2477   c->gdt[SEG_UDATA] = SEG(STA_W, 0, 0xffffffff, DPL_USER);
2478 
2479   // Map cpu, and curproc
2480   c->gdt[SEG_KCPU] = SEG(STA_W, &c->cpu, 8, 0);
2481 
2482   lgdt(c->gdt, sizeof(c->gdt));
2483   loadgs(SEG_KCPU << 3);
2484 
2485   // Initialize cpu-local storage.
2486   cpu = c;
2487   proc = 0;
2488 }
2489 
2490 
2491 
2492 
2493 
2494 
2495 
2496 
2497 
2498 
2499 
2500 // Return the address of the PTE in page table pgdir
2501 // that corresponds to linear address va.  If create!=0,
2502 // create any required page table pages.
2503 static pte_t *
2504 walkpgdir(pde_t *pgdir, const void *va, int create)
2505 {
2506   uint r;
2507   pde_t *pde;
2508   pte_t *pgtab;
2509 
2510   pde = &pgdir[PDX(va)];
2511   if(*pde & PTE_P){
2512     pgtab = (pte_t*) PTE_ADDR(*pde);
2513   } else if(!create || !(r = (uint) kalloc()))
2514     return 0;
2515   else {
2516     pgtab = (pte_t*) r;
2517     // Make sure all those PTE_P bits are zero.
2518     memset(pgtab, 0, PGSIZE);
2519     // The permissions here are overly generous, but they can
2520     // be further restricted by the permissions in the page table
2521     // entries, if necessary.
2522     *pde = PADDR(r) | PTE_P | PTE_W | PTE_U;
2523   }
2524   return &pgtab[PTX(va)];
2525 }
2526 
2527 // Create PTEs for linear addresses starting at la that refer to
2528 // physical addresses starting at pa. la and size might not
2529 // be page-aligned.
2530 static int
2531 mappages(pde_t *pgdir, void *la, uint size, uint pa, int perm)
2532 {
2533   char *a = PGROUNDDOWN(la);
2534   char *last = PGROUNDDOWN(la + size - 1);
2535 
2536   while(1){
2537     pte_t *pte = walkpgdir(pgdir, a, 1);
2538     if(pte == 0)
2539       return 0;
2540     if(*pte & PTE_P)
2541       panic("remap");
2542     *pte = pa | perm | PTE_P;
2543     if(a == last)
2544       break;
2545     a += PGSIZE;
2546     pa += PGSIZE;
2547   }
2548   return 1;
2549 }
2550 // The mappings from logical to linear are one to one (i.e.,
2551 // segmentation doesn't do anything).
2552 // There is one page table per process, plus one that's used
2553 // when a CPU is not running any process (kpgdir).
2554 // A user process uses the same page table as the kernel; the
2555 // page protection bits prevent it from using anything other
2556 // than its memory.
2557 //
2558 // setupkvm() and exec() set up every page table like this:
2559 //   0..640K          : user memory (text, data, stack, heap)
2560 //   640K..1M         : mapped direct (for IO space)
2561 //   1M..end          : mapped direct (for the kernel's text and data)
2562 //   end..PHYSTOP     : mapped direct (kernel heap and user pages)
2563 //   0xfe000000..0    : mapped direct (devices such as ioapic)
2564 //
2565 // The kernel allocates memory for its heap and for user memory
2566 // between kernend and the end of physical memory (PHYSTOP).
2567 // The virtual address space of each user program includes the kernel
2568 // (which is inaccessible in user mode).  The user program addresses
2569 // range from 0 till 640KB (USERTOP), which where the I/O hole starts
2570 // (both in physical memory and in the kernel's virtual address
2571 // space).
2572 
2573 // Allocate one page table for the machine for the kernel address
2574 // space for scheduler processes.
2575 void
2576 kvmalloc(void)
2577 {
2578   kpgdir = setupkvm();
2579 }
2580 
2581 // Set up kernel part of a page table.
2582 pde_t*
2583 setupkvm(void)
2584 {
2585   pde_t *pgdir;
2586 
2587   // Allocate page directory
2588   if(!(pgdir = (pde_t *) kalloc()))
2589     return 0;
2590   memset(pgdir, 0, PGSIZE);
2591   if(// Map IO space from 640K to 1Mbyte
2592      !mappages(pgdir, (void *)USERTOP, 0x60000, USERTOP, PTE_W) ||
2593      // Map kernel and free memory pool
2594      !mappages(pgdir, (void *)0x100000, PHYSTOP-0x100000, 0x100000, PTE_W) ||
2595      // Map devices such as ioapic, lapic, ...
2596      !mappages(pgdir, (void *)0xFE000000, 0x2000000, 0xFE000000, PTE_W))
2597     return 0;
2598   return pgdir;
2599 }
2600 // Turn on paging.
2601 void
2602 vmenable(void)
2603 {
2604   uint cr0;
2605 
2606   switchkvm(); // load kpgdir into cr3
2607   cr0 = rcr0();
2608   cr0 |= CR0_PG;
2609   lcr0(cr0);
2610 }
2611 
2612 // Switch h/w page table register to the kernel-only page table,
2613 // for when no process is running.
2614 void
2615 switchkvm()
2616 {
2617   lcr3(PADDR(kpgdir));   // switch to the kernel page table
2618 }
2619 
2620 // Switch h/w page table and TSS registers to point to process p.
2621 void
2622 switchuvm(struct proc *p)
2623 {
2624   pushcli();
2625 
2626   // Setup TSS
2627   cpu->gdt[SEG_TSS] = SEG16(STS_T32A, &cpu->ts, sizeof(cpu->ts)-1, 0);
2628   cpu->gdt[SEG_TSS].s = 0;
2629   cpu->ts.ss0 = SEG_KDATA << 3;
2630   cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE;
2631   ltr(SEG_TSS << 3);
2632 
2633   if(p->pgdir == 0)
2634     panic("switchuvm: no pgdir\n");
2635 
2636   lcr3(PADDR(p->pgdir));  // switch to new address space
2637   popcli();
2638 }
2639 
2640 
2641 
2642 
2643 
2644 
2645 
2646 
2647 
2648 
2649 
2650 // Return the physical address that a given user address
2651 // maps to.  The result is also a kernel logical address,
2652 // since the kernel maps the physical memory allocated to user
2653 // processes directly.
2654 char*
2655 uva2ka(pde_t *pgdir, char *uva)
2656 {
2657   pte_t *pte = walkpgdir(pgdir, uva, 0);
2658   if(pte == 0) return 0;
2659   uint pa = PTE_ADDR(*pte);
2660   return (char *)pa;
2661 }
2662 
2663 // Load the initcode into address 0 of pgdir.
2664 // sz must be less than a page.
2665 void
2666 inituvm(pde_t *pgdir, char *init, uint sz)
2667 {
2668   char *mem = kalloc();
2669   if (sz >= PGSIZE)
2670     panic("inituvm: more than a page");
2671   memset(mem, 0, PGSIZE);
2672   mappages(pgdir, 0, PGSIZE, PADDR(mem), PTE_W|PTE_U);
2673   memmove(mem, init, sz);
2674 }
2675 
2676 // Load a program segment into pgdir.  addr must be page-aligned
2677 // and the pages from addr to addr+sz must already be mapped.
2678 int
2679 loaduvm(pde_t *pgdir, char *addr, struct inode *ip, uint offset, uint sz)
2680 {
2681   uint i, pa, n;
2682   pte_t *pte;
2683 
2684   if((uint)addr % PGSIZE != 0)
2685     panic("loaduvm: addr must be page aligned\n");
2686   for(i = 0; i < sz; i += PGSIZE){
2687     if(!(pte = walkpgdir(pgdir, addr+i, 0)))
2688       panic("loaduvm: address should exist\n");
2689     pa = PTE_ADDR(*pte);
2690     if(sz - i < PGSIZE) n = sz - i;
2691     else n = PGSIZE;
2692     if(readi(ip, (char *)pa, offset+i, n) != n)
2693       return 0;
2694   }
2695   return 1;
2696 }
2697 
2698 
2699 
2700 // Allocate memory to the process to bring its size from oldsz to
2701 // newsz. Allocates physical memory and page table entries. oldsz and
2702 // newsz need not be page-aligned, nor does newsz have to be larger
2703 // than oldsz.  Returns the new process size or 0 on error.
2704 int
2705 allocuvm(pde_t *pgdir, uint oldsz, uint newsz)
2706 {
2707   if(newsz > USERTOP)
2708     return 0;
2709   char *a = (char *)PGROUNDUP(oldsz);
2710   char *last = PGROUNDDOWN(newsz - 1);
2711   for (; a <= last; a += PGSIZE){
2712     char *mem = kalloc();
2713     if(mem == 0){
2714       cprintf("allocuvm out of memory\n");
2715       deallocuvm(pgdir, newsz, oldsz);
2716       return 0;
2717     }
2718     memset(mem, 0, PGSIZE);
2719     mappages(pgdir, a, PGSIZE, PADDR(mem), PTE_W|PTE_U);
2720   }
2721   return newsz > oldsz ? newsz : oldsz;
2722 }
2723 
2724 // Deallocate user pages to bring the process size from oldsz to
2725 // newsz.  oldsz and newsz need not be page-aligned, nor does newsz
2726 // need to be less than oldsz.  oldsz can be larger than the actual
2727 // process size.  Returns the new process size.
2728 int
2729 deallocuvm(pde_t *pgdir, uint oldsz, uint newsz)
2730 {
2731   char *a = (char *)PGROUNDUP(newsz);
2732   char *last = PGROUNDDOWN(oldsz - 1);
2733   for(; a <= last; a += PGSIZE){
2734     pte_t *pte = walkpgdir(pgdir, a, 0);
2735     if(pte && (*pte & PTE_P) != 0){
2736       uint pa = PTE_ADDR(*pte);
2737       if(pa == 0)
2738         panic("kfree");
2739       kfree((void *) pa);
2740       *pte = 0;
2741     }
2742   }
2743   return newsz < oldsz ? newsz : oldsz;
2744 }
2745 
2746 
2747 
2748 
2749 
2750 // Free a page table and all the physical memory pages
2751 // in the user part.
2752 void
2753 freevm(pde_t *pgdir)
2754 {
2755   uint i;
2756 
2757   if(!pgdir)
2758     panic("freevm: no pgdir");
2759   deallocuvm(pgdir, USERTOP, 0);
2760   for(i = 0; i < NPDENTRIES; i++){
2761     if(pgdir[i] & PTE_P)
2762       kfree((void *) PTE_ADDR(pgdir[i]));
2763   }
2764   kfree((void *) pgdir);
2765 }
2766 
2767 // Given a parent process's page table, create a copy
2768 // of it for a child.
2769 pde_t*
2770 copyuvm(pde_t *pgdir, uint sz)
2771 {
2772   pde_t *d = setupkvm();
2773   pte_t *pte;
2774   uint pa, i;
2775   char *mem;
2776 
2777   if(!d) return 0;
2778   for(i = 0; i < sz; i += PGSIZE){
2779     if(!(pte = walkpgdir(pgdir, (void *)i, 0)))
2780       panic("copyuvm: pte should exist\n");
2781     if(!(*pte & PTE_P))
2782       panic("copyuvm: page not present\n");
2783     pa = PTE_ADDR(*pte);
2784     if(!(mem = kalloc()))
2785       goto bad;
2786     memmove(mem, (char *)pa, PGSIZE);
2787     if(!mappages(d, (void *)i, PGSIZE, PADDR(mem), PTE_W|PTE_U))
2788       goto bad;
2789   }
2790   return d;
2791 
2792 bad:
2793   freevm(d);
2794   return 0;
2795 }
2796 
2797 
2798 
2799 
